// STL
#include <algorithm>   // std::minmax_element
#include <cmath>       // std::sqrt()
#include <vector>      // std::vector

// jScience
#include "jstats.hpp"  // mean(), variance()

// stats++
#include "statsxx/dataset/DataSet.hpp" // DataSet


//========================================================================
//========================================================================
//
// NAME: void get_TS_stats(const DataSet & TS, std::vector<double> & inp_min,  std::vector<double> & inp_max,  std::vector<double> & inp_mean,  std::vector<double> & inp_var,  std::vector<double> & inp_stddev, std::vector<double> & out_min,  std::vector<double> & out_max,  std::vector<double> & out_mean,  std::vector<double> & out_var,  std::vector<double> & out_stddev )
//
// DESC: Calculates the statistical properties (min, max, mean, *sample* variance, and *sample* standard deviation) of a training set.
//
// NOTES:
//     ! due to the fact that inputs and outputs are (probably) similar temporally, only the tdelay[0] positions are used below to calculate statistics
//
//========================================================================
//========================================================================
inline void get_TS_stats(const DataSet &TS, std::vector<double> &inp_min,  std::vector<double> &inp_max,  std::vector<double> &inp_mean,  std::vector<double> &inp_var,  std::vector<double> &inp_stddev, std::vector<double> &out_min,  std::vector<double> &out_max,  std::vector<double> &out_mean,  std::vector<double> &out_var,  std::vector<double> &out_stddev )
{
    int n  = TS.pt.size();
    int ni = TS.pt[0].in[0].size();
    int no = TS.pt[0].out.size();

    inp_min.resize(ni);
    inp_max.resize(ni);
    inp_mean.resize(ni);
    inp_var.resize(ni);
    inp_stddev.resize(ni);

    out_min.resize(no);
    out_max.resize(no);
    out_mean.resize(no);
    out_var.resize(no);
    out_stddev.resize(no);

    for(int i = 0; i < ni; ++i)
    {
        std::vector<double> x;
        for(int j = 0; j < n; ++j)
        {
            x.push_back(TS.pt[j].in[0][i]);
        }

        auto result = std::minmax_element(x.begin(), x.end());
        inp_min[i] = *result.first;
        inp_max[i] = *result.second;
        inp_mean[i]   = mean(x);
        inp_var[i]    = variance(x);
        inp_stddev[i] = std::sqrt(inp_var[i]);
    }

    for(int i = 0; i < no; ++i)
    {
        std::vector<double> x;
        for(int j = 0; j < n; ++j)
        {
            x.push_back(TS.pt[j].out[i]);
        }

        auto result = std::minmax_element(x.begin(), x.end());
        out_min[i] = *result.first;
        out_max[i] = *result.second;
        out_mean[i]   = mean(x);
        out_var[i]    = variance(x);
        out_stddev[i] = std::sqrt(out_var[i]);
    }
}
